# coding: utf-8
from datetime import datetime, timedelta

from django.core.cache import cache
from django.db import models
from django.db.models.functions import Coalesce

from lib.common import BasicManager, CacheKeys
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.conf import settings
from django.db.models import Q, Count, Sum, F
from project.settings import DEFAULT_PAGESIZE


class ModelManagerCourse(BasicManager):

    # 获取课程的章节数
    def get_chapter_nums(self):
        return self.chapter.all().count()

    # 获取课程列表
    def get_course_list(self, page, is_show=None, name=None, category=None, keyword=None):
        result = self.values("id", "name", "desc", "students", "thumb", "charge", "is_show",
                             "category__name").order_by("-created_at")
        if is_show:
            result = result.filter(is_show=is_show)
        if name:
            result = result.filter(Q(name__icontains=name))
        if category:
            result = result.filter(category_id=category)
        if keyword:
            result = result.filter(name__icontains=keyword)
        paginator = Paginator(result, DEFAULT_PAGESIZE)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages, 'retcode': 0}

    def create_course(self, param_dict):
        require_paras = [
            'name', 'desc', 'detail', 'thumb', 'charge', 'original_charge', 'category_id',
        ]
        add_param_dict = {}
        for para in require_paras:
            add_param_dict[para] = param_dict[para]
        course = self.model(**add_param_dict)
        course.save()

    def get_courses_for_name(self, page):
        result = self.filter(is_show=1).values('id', 'name', 'thumb').order_by("-created_at")
        paginator = Paginator(result, 600)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous()}

    def get_course_by_id(self, courseid):
        cache_key = CacheKeys.course % courseid
        course = cache.get(cache_key)

        if not course:
            course = self.filter(id=courseid).values().first()
            if course:
                cache.set(cache_key, course, 1800)
        return course


class ModelManagerCourseCategory(BasicManager):

    def get_category_list(self, is_show):
        return sorted(list(self.filter(is_show=is_show).values()), key=lambda x: x["sort"])

    def get_category(self, page):
        result = self.values().order_by("-sort")
        if not page:
            return {'retcode': 0, 'retlist': list(result)}
        paginator = Paginator(result, DEFAULT_PAGESIZE)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_category_for_course(self):
        return self.course_set.all()

    def get_course_nums(self):
        return self.course_set.all().count()


class ModelManagerChapter(BasicManager):

    # 根据课程ID获取章节
    def get_chapter_for_course(self, page, course_id, is_show=None, need_detail=False):
        if need_detail:
            result = self.filter(course=course_id).values(
                'name', 'sort', 'id', 'duration', 'view_num', 'free_seconds', 'created_at', 'short_description', "types"
            ).order_by("sort")
        else:
            result = self.filter(course=course_id).values('name', 'sort', 'id').order_by("-sort")
        if is_show:
            result = result.filter(is_show=1)
        if not page:
            return {'retcode': 0, 'retlist': list(result)}
        paginator = Paginator(result, DEFAULT_PAGESIZE)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}

        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_url_for_courseAndchapter(self, course_id, chapter_id):
        result = Chapter.objects.filter(is_show=1, course=course_id, chapter=chapter_id)\
                .values('id', 'name', 'charge', 'duration', 'view_num', 'course__name', 'short_description',
                        'render_desc', 'is_show', 'created_at', 'is_ban_sell', 'types', 'free_seconds',
                        'comment_status')
        return result

    # 获取播放地址
    def get_url(self, chapter_id):
        result = Chapter.objects.filter(is_show=1, chapter=chapter_id).values('url', 'duration', 'free_seconds')
        return result

    def get_chapter_by_id(self, chapterid):
        cache_key = CacheKeys.chapter % chapterid
        chapter = cache.get(cache_key)

        if not chapter:
            chapter = self.filter(id=chapterid).values().first()
            if chapter:
                cache.set(cache_key, chapter, 1800)
        return chapter

    def get_videos_by_course(self, page, course_id, chapter_id, direction=1, is_show=None, user_id=None):
        """
        app点进一个章节视频的时候，需要当前页面可以切换听其他章节的课程
        :param user_id: 如果需要某个用户各个视频观看的进度，需要传这个参数
        :param direction:
        :param chapter_id:
        :param page:
        :param course_id:
        :param is_show:
        :return:
        """
        result = self.filter(course_id=course_id).values(
            'thumb', 'url', 'name', 'sort', 'id', 'duration', 'view_num', 'free_seconds', 'created_at',
            'short_description', 'render_desc', 'types').order_by("sort")
        if is_show:
            result = result.filter(is_show=1)
        if direction == 0:
            result = result.filter(sort__lt=chapter_id)
        else:
            result = result.filter(sort__gte=chapter_id)
        if not page:
            return {'retcode': 0, 'retlist': list(result)}
        paginator = Paginator(result, DEFAULT_PAGESIZE)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}

        final_list = list(result_page)
        if user_id:
            chapter_ids = [item['id'] for item in final_list]
            tmp = mm_UserVideoWatchRecords.filter(user_id=user_id,
                                                  chapter_id__in=chapter_ids).values('chapter_id', 'last_watch_seconds')
            tmp_dict = {item['chapter_id']: item['last_watch_seconds'] for item in tmp}
            for item in final_list:
                item['last_watch_seconds'] = tmp_dict[item['id']] if item['id'] in tmp_dict else 0
        return {'retlist': final_list, 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous()}


class ModelManagerExperience(BasicManager):
    def get_experience_list(self, count=0, page=0):
        """

        :param count: 获取几个，首页默认获取3个，前端传
        :param page: 获取第几页数据，跟count参数二选一，如果传了count，忽略这个参数
        :return:
        """
        results = Experience.objects.filter(is_show=1).values()
        if count:
            return {'retcode': 0, 'data': list(results[:count])}
        paginator = Paginator(results, DEFAULT_PAGESIZE)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage:
            result_page = paginator.page(paginator.num_pages)

        return {'retcode': 0, 'data': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous()}

    def get_experience(self, page, is_show=None, name=None):
        result = self.values().order_by("-created_at")
        if is_show:
            result = result.filter(is_show=is_show)
        if name:
            result = result.filter(Q(name__icontains=name))
        paginator = Paginator(result, DEFAULT_PAGESIZE)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}

        return {'data': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_experience_byid(self, eid):
        ret = list(self.filter(pk=eid).values())
        return {'retcode': 0, 'data': ret[0] if len(ret) > 0 else None}


class ModelManagerCourseUserRecords(BasicManager):

    def get_read_history(self, uid, count=0, page=0):
        """
        :param uid: 用户auth_user表id
        :param count: 获取几个(首页专用)，首页默认获取2个, 以课程为单位
        :param page: 获取第几页数据，跟count参数二选一，如果传了count，忽略这个参数
        :return:
        """
        results = mm_CourseUserRecords.filter(user_id=uid).select_related("course").order_by(
            "-updated_at").values("updated_at", "course_id", "progress",
                                  "course__name", "course__thumb", "course__is_show")
        # results = CourseUserRecords.objects.filter(user_id=uid).select_related("course").order_by(
        #     "-day").values("day").annotate(cids=Count("course_id"), data=GroupConcat("progress", "course__name"))
        if count:
            course_records = list(results[:count])
            for cr in course_records:
                chapter = UserVideoWatchRecords.objects.select_related("chapter").filter(
                    user_id=uid, course_id=cr["course_id"]).order_by("-updated_at").values(
                    "chapter__name", "chapter_id", "chapter__sort").first()
                cr["chapter"] = chapter
            return {'retcode': 0, 'data': course_records}

        elif page:
            paginator = Paginator(results, settings.DEFAULT_PAGESIZE)
            try:
                result_page = paginator.page(page)
            except PageNotAnInteger:
                result_page = paginator.page(1)
            except EmptyPage:
                result_page = paginator.page(paginator.num_pages)

            course_records = list(result_page)
            summary = mm_UserVideoWatchRecords.filter(user_id=uid).aggregate(nums=Count("id"),
                                                                             seconds=Sum("max_watch_seconds"))
            # ret = {}
            # for cr in course_records:
            #     if str(cr['day']) in ret:
            #         ret[str(cr['day'])].append(cr)
            #     else:
            #         ret[str(cr['day'])] = [cr]

            return {'retcode': 0, 'data': course_records, 'summary': summary, 'curpageidx': page,
                    'hasnext': result_page.has_next(),
                    'hasprevious': result_page.has_previous()}

    def get_course_records_list(self, page, course_id, user_id=None, start_date=None, end_date=None):
        results = self.filter(course_id=course_id).select_related("user").order_by(
            "-updated_at").values("day", "course_id", "progress", "user__student__nick_name",
                                  "user__student__role_expired_at", "created_at", "is_watched", "watched_at")
        if user_id:
            results.filter(user_id=user_id)
        if start_date:
            query = Q(created_at__range=[start_date, end_date])
            results.filter(query)
        paginator = Paginator(results, 15)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}

        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}


class ModelManagerUserVideoWatchRecords(BasicManager):
    def update_read_history(self, userid, chapterid, seconds):
        """
        异步任务专属调用
        :param userid:  auth_user表id
        :param chapterid:
        :param seconds:
        :return:
        """
        uvr = self.get_or_default(user_id=userid, chapter_id=chapterid)
        if uvr:
            uvr.last_watch_seconds = seconds
            uvr.save()
            if seconds > uvr.max_watch_seconds:
                uvr.max_watch_seconds = seconds
                uvr.save()
                self.update_course_progress(userid, uvr.course_id)
        else:
            chapter = mm_Chapter.get(pk=chapterid)
            chapter.view_num = chapter.view_num + 1
            chapter.save()
            uvr = self.model(user_id=userid, chapter_id=chapterid, course_id=chapter.course_id,
                             last_watch_seconds=seconds, max_watch_seconds=seconds)
            uvr.save()
            self.update_course_progress(userid, chapter.course_id)
        # 记录每一次观看时长
        mm_UserRecordsDetails.update_watch_time(userid, chapterid, seconds)

    def update_course_progress(self, userid, courseid):
        cur = mm_CourseUserRecords.get_or_default(user_id=userid, course_id=courseid)
        total = mm_Chapter.filter(course_id=courseid).aggregate(sum=Coalesce(Sum("duration"), 0))['sum']
        see_total = mm_UserVideoWatchRecords.filter(user_id=userid, course_id=courseid).aggregate(
            sum=Coalesce(Sum("max_watch_seconds"), 0))['sum']
        if cur:
            cur.progress = int(see_total/total*100)
            cur.save()
        else:
            mm_CourseUserRecords.create(course_id=courseid, user_id=userid, progress=int(see_total/total*100))
            mm_Course.filter(id=courseid).update(students=F("students")+1)


class ModelManegerUserRecordsDetails(BasicManager):

    def update_watch_time(self, userid, chapterid, seconds):
        today = datetime.now()
        q1 = Q(created_at__range=[(today).strftime('%Y-%m-%d 00:00:00'), today.strftime('%Y-%m-%d 23:59:59')])
        # q1 = Q(created_at__range=['2021-08-24 00:00:00', '2021-08-24 23:59:59'])
        q2 = Q(user_id=userid, chapter=chapterid)
        report_details = self.filter(q1 & q2).first()
        if report_details:
            report_details.watch_seconds = seconds
            report_details.save()
        else:
            last_report_details = self.filter(q2).values('watch_seconds').order_by('-created_at').first()
            last_watch_seconds = last_report_details.get('watch_seconds') if last_report_details else 0
            # 上一次观看时长和视频总时长差10s以内，即重新从0开始观看
            if mm_Chapter.get(pk=chapterid).duration - last_watch_seconds <= 10:
                last_watch_seconds = 0
            self.create(user_id=userid, chapter_id=chapterid, last_watch_seconds=last_watch_seconds, watch_seconds=seconds)

    def get_study_report(self, u_id):
        """
        获取学习报告
        @param u_id: user_id
        @return:
        """

        data = []
        today = datetime.now()
        for i in range(7):  # 当前日期往前七天的时间段
            offset = timedelta(days=-i)
            range_time = [(today + offset).strftime('%Y-%m-%d 00:00:00'), (today + offset).strftime('%Y-%m-%d 23:59:59')]
            res = self.filter(
                created_at__range=range_time,
                user_id=u_id,
            )
            nums = res.values('chapter').distinct().count()
            # 最后一次观看时长大于前一次观看时长，则取差值
            seconds_1 = res.filter(watch_seconds__gt=F('last_watch_seconds')).aggregate(
                seconds=Sum(F('watch_seconds') - F('last_watch_seconds'))
            ).get('seconds')
            # 最后一次观看时长小于前一次观看时长，则取最后一次观看值
            seconds_2 = res.filter(watch_seconds__lt=F('last_watch_seconds')).aggregate(
                seconds=Sum(F('watch_seconds'))
            ).get('seconds')
            seconds_1 = seconds_1 if seconds_1 else 0
            seconds_2 = seconds_2 if seconds_2 else 0
            seconds = seconds_1 + seconds_2
            data.append({'date': (today + offset).strftime('%Y-%m-%d'), 'seconds': seconds, 'nums': nums})
        total_nums = self.filter(
            user_id=u_id,
            created_at__range=[(today + timedelta(days=-6)).strftime('%Y-%m-%d 00:00:00'), today.strftime('%Y-%m-%d 23:59:59')]
        ).values('chapter').distinct().count()
        return {
            "seven_data": data,
            'longest_seconds': max([i['seconds'] for i in data]),
            'total_seconds': sum([i['seconds'] for i in data]),
            'total_nums': total_nums
        }

class Category(models.Model):
    sort = models.IntegerField("排序", default=0)
    name = models.CharField("名称", max_length=50)
    thumb = models.CharField("图标", max_length=200)
    is_show = models.PositiveSmallIntegerField("是否显示", default=0)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerCourseCategory()

    class Meta:
        verbose_name = '课程分类'
        verbose_name_plural = verbose_name
        db_table = "momself_category"

    def __str__(self):
        return self.name


class Course(models.Model):
    name = models.CharField("课程名", max_length=50)
    desc = models.CharField("课程描述", max_length=300)
    detail = models.TextField("课程详情")
    # duration = models.IntegerField("时长(秒数)", default=0)
    students = models.IntegerField("学习人数", default=0)
    fav_nums = models.IntegerField("收藏人数", default=0)
    thumb = models.ImageField("封面图", max_length=200)
    click_nums = models.IntegerField("点击数", default=0)
    tag = models.CharField('课程标签', default='', max_length=10)
    is_banner = models.BooleanField('是否轮播', default=False)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)
    charge = models.IntegerField('课程价格', default=0)  # 单位分
    original_charge = models.IntegerField("划线价格", default=0)
    is_show = models.PositiveSmallIntegerField("是否显示", default=0)
    category = models.ForeignKey(Category, verbose_name='所属分类')
    is_free = models.PositiveSmallIntegerField("是否免费", default=0)
    is_role = models.PositiveSmallIntegerField("是否VIP免费看", default=0)
    comment_status = models.PositiveSmallIntegerField("是否可以评论,	0关闭评论,1所有人,2仅购买	", default=0)

    objects = ModelManagerCourse()

    class Meta:
        verbose_name = '课程'
        verbose_name_plural = verbose_name
        db_table = "momself_course"

    def __str__(self):
        return self.name

    def toJSON(self):
        import json
        return json.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))


class Chapter(models.Model):
    course = models.ForeignKey(Course, verbose_name='课程', on_delete=models.CASCADE, related_name="chapter")
    name = models.CharField("章节名", max_length=100)
    thumb = models.ImageField("封面图", max_length=200, default='')
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)
    is_show = models.PositiveSmallIntegerField("是否显示", default=0)
    url = models.CharField("播放地址", max_length=200, default='')
    charge = models.IntegerField('价格', default=0)
    duration = models.IntegerField("时长(秒数)", default=0)
    view_num = models.IntegerField("观看次数", default=0)
    short_description = models.TextField("简短介绍", null=True, default='', blank=True)
    render_desc = models.TextField("简介", null=True, default='', blank=True)
    published_at = models.DateTimeField("上线时间", default=datetime.now)
    is_ban_sell = models.PositiveSmallIntegerField("禁止售卖,0否,1是", default=0)
    types = models.PositiveSmallIntegerField("类型 1视频,2音频", default=1)
    free_seconds = models.IntegerField("试看秒数", null=True, default=0)
    comment_status = models.PositiveSmallIntegerField("是否可以评论 0禁止评论,1所有人,2仅购买", default=0)
    sort = models.IntegerField("排序", default=0)  # 顺序排，譬如1表示第一章，2表示第二章

    class Meta:
        verbose_name = "章节"
        verbose_name_plural = verbose_name
        db_table = "momself_chapter"

    objects = ModelManagerChapter()

    def __str__(self):
        return '《{0}》课程的章节 >> {1}'.format(self.course, self.name)


class Experience(models.Model):
    url = models.CharField("播放地址", max_length=200, default='')
    name = models.CharField("课程名", max_length=50)
    render_desc = models.TextField("简介", null=True, blank=True)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)
    is_show = models.PositiveSmallIntegerField("是否显示", default=0)
    published_at = models.DateTimeField("上线时间", default=datetime.now)
    duration = models.IntegerField("时长(秒数)", default=0)
    thumb = models.ImageField("封面图", max_length=200)

    class Meta:
        verbose_name = "免费音频"
        verbose_name_plural = verbose_name
        db_table = "momself_experience"

    objects = ModelManagerExperience()

    def __str__(self):
        return self.name


class CourseUserRecords(models.Model):
    course = models.ForeignKey(Course)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)
    is_watched = models.PositiveSmallIntegerField("是否看完", default=0)  # 0:未看完  1:看完  # 暂时无用，并未更新
    watched_at = models.DateTimeField("看完时间", null=True)  # 暂时无用，并未更新
    progress = models.IntegerField("观看进度", default=0)
    day = models.DateField("日期", null=True)  # 无用，并未更新

    class Meta:
        verbose_name = "用户观看课程记录"
        verbose_name_plural = verbose_name
        db_table = "momself_course_user_records"
        unique_together = [("user", "course")]

    objects = ModelManagerCourseUserRecords()


class UserVideoWatchRecords(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    course = models.ForeignKey(Course)
    chapter = models.ForeignKey(Chapter, on_delete=models.SET_NULL, null=True)
    last_watch_seconds = models.IntegerField("上一次观看秒数", default=0)  # app自动定位至上一次观看点
    max_watch_seconds = models.IntegerField("最大观看秒数", default=0)  # 用于统计课程观看进度
    watched_at = models.DateTimeField("看完时间", null=True)  # 暂时无用，并未更新
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = ModelManagerUserVideoWatchRecords()

    class Meta:
        db_table = "momself_user_video_watch_records"
        unique_together = [("user", "chapter")]

class UserRecordsDetails(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    chapter = models.ForeignKey(Chapter, on_delete=models.SET_NULL, null=True)
    last_watch_seconds = models.IntegerField("上一次观看时长", default=0)
    watch_seconds =  models.IntegerField("当天观看时长", default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    object = ModelManegerUserRecordsDetails()

    class Meta:
        db_table = "momself_user_record_details"

mm_Chapter = Chapter.objects
mm_Course = Course.objects
mm_Category = Category.objects
mm_Experience = Experience.objects
mm_CourseUserRecords = CourseUserRecords.objects
mm_UserVideoWatchRecords = UserVideoWatchRecords.objects
mm_UserRecordsDetails = UserRecordsDetails.object